package edu.mapi.aamas.operator;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.LinkedHashMap;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.vecmath.Point3d;

import edu.mapi.aamas.behaviors.TaskInitiator;
import edu.mapi.aamas.common.Task;
import edu.mapi.aamas.common.VehicleState;
import edu.mapi.aamas.common.WorldState;
/**
 * @author ZP
 */
public class Renderer2DPanel extends JPanel {

	private double startX = -500, startY = 200;
	private WorldState state = new WorldState();
	private Point2D lastDragPoint = null;
	private JLabel statusLabel = new JLabel();
	private Point3d pt = null;	
	
	private Image otaImage = getImage("images/ota.png");
	
	private OperatorAgent agent;
	
	private LinkedHashMap<String, Image> vehImages = new LinkedHashMap<String, Image>();
	
	public Point3d getRealWorldPoint(Point2D screenPoint) {
		double x = startX;
		double y = startY;
		double z = 0;
		
		x += screenPoint.getX();
		y -= screenPoint.getY();
		
		return new Point3d(x, y, z);
	}
	
	public Point2D getScreenPosition(Point3d pt) {
		Point2D.Double point = new Point2D.Double();
		point.x = pt.x - startX;
		point.y = -(pt.y - startY);
		
		return point;
	}
	
	public Image getImage(String path) {
		try {
			return new ImageIcon(getClass().getClassLoader().getResource(path)).getImage();
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public Renderer2DPanel(OperatorAgent agent) {
		super();
		
		vehImages.put("default", getImage("images/apv.png"));
		vehImages.put("apv", getImage("images/apv.png"));
		vehImages.put("lusitania", getImage("images/lusitania.png"));
		vehImages.put("antex-m", getImage("images/antex-m.png"));
		vehImages.put("brutus", getImage("images/brutus.png"));
		
		this.agent = agent;
		statusLabel = new JLabel("test");
		statusLabel.setOpaque(true);
		statusLabel.setBackground(new Color(255,255,255,75));
		statusLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
		
		setBackground(new Color(100, 100, 150));

		addMouseListener(new MouseAdapter() {

			public void mousePressed(MouseEvent e) {
				super.mousePressed(e);
				lastDragPoint = e.getPoint();
			}

			public void mouseReleased(MouseEvent e) {
				super.mouseReleased(e);
				lastDragPoint = null;
			}

			public void mouseClicked(MouseEvent e) {
				super.mouseClicked(e);

				if (e.getButton() != MouseEvent.BUTTON3)
					return;

				JPopupMenu popup = new JPopupMenu();
				final Point2D pt = e.getPoint();
				JMenuItem item = new JMenuItem("Create Goto Task");
				item.addActionListener(new ActionListener() {
					public void actionPerformed(java.awt.event.ActionEvent arg0) {
						Task task = new Task();
						
						
						Point3d pt2 = getRealWorldPoint(pt); 
						task.addPoint(pt2);
						
						task.setId("GoTo("+(int)pt2.x+","+pt2.y+")");						
						getAgent().addBehaviour(new TaskInitiator(getAgent(), task, state.getKnownVehicleIds()));
					}
				});					
				popup.add(item);
				
				popup.show(Renderer2DPanel.this, e.getX(), e.getY());
			}
		});



		addMouseMotionListener(new MouseMotionAdapter() {

			
			@Override
			public void mouseMoved(MouseEvent e) {
				super.mouseMoved(e);
				pt = getRealWorldPoint(e.getPoint());				
			}
			public void mouseDragged(MouseEvent e) {
				if (lastDragPoint == null) {
					lastDragPoint =e.getPoint();
					return;
				}

				double deltaX = e.getPoint().getX() - lastDragPoint.getX();
				double deltaY = e.getPoint().getY() - lastDragPoint.getY();

				double tx, ty;
				tx = deltaX;
				ty = deltaY;

				startX -= tx;
				startY += ty;

				lastDragPoint = e.getPoint();
				repaint();
			}
		});
	}

	public void paint(Graphics g) {
		super.paint(g);

		//TODO paint Map...

		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

		g2.drawString(getRealWorldPoint(new Point2D.Double()).toString(), 10, 10);
		AffineTransform normalTransform = g2.getTransform();
		String statusText = "<html>";
		
		Point2D pt2 = getScreenPosition(new Point3d(0,0,0));
		g2.translate(pt2.getX(), pt2.getY());
		g2.scale(3.625, 3.625);
		g2.drawImage(otaImage, -1016, -712, null);
		
		for (VehicleState vs : state.getVehicleStates()) {
			g2.setTransform(new AffineTransform());
			Point2D pt = getScreenPosition(vs.getPoint());
			
			if (vs.getDestination() != null) {
				Point2D target = getScreenPosition(vs.getDestination());
				//g2.setColor(new Color(255,0,0));
				g2.setStroke(new BasicStroke(2));
				g2.setColor(new Color(255,0,0,75));
				g2.draw(new Line2D.Double(pt.getX(), pt.getY(), target.getX(), target.getY()));
				g2.setColor(new Color(255,0,0));
				g2.draw(new Ellipse2D.Double(target.getX()-10, target.getY()-10, 20, 20));
				g2.setColor(new Color(255,0,0,75));
				g2.fill(new Ellipse2D.Double(target.getX()-10, target.getY()-10, 20, 20));
			}
			
			g2.translate(pt.getX(), pt.getY());
			
			g2.setColor(Color.white);
			g2.drawString(vs.getId(), 10, 10);
						
			g2.rotate(-vs.getYaw()+Math.PI/2);
			
			Image img;
			
			if (vehImages.containsKey(vs.getModel()))
				img = vehImages.get(vs.getModel());
			else
				img = vehImages.get("default");
		
			int width = img.getWidth(null);
			int height = img.getWidth(null);
			//g2.scale(0.1, 0.1);
			g2.drawImage(img, -width/2, -height/2, null);			
			statusText = statusText + "<font color='red'>"+vs.getId()+"</font> ("+((int)vs.getPoint().x)+", "+((int)vs.getPoint().y)+") f="+((int)vs.getFuel())+", yaw="+(int)Math.toDegrees(vs.getYaw())+"<br>";			
		}

		g2.setTransform(new AffineTransform());
		if (pt != null)
			statusText = statusText + "Pointer: ("+(int)pt.x+", "+(int)pt.y+")";
		g2.translate(getWidth() - statusLabel.getPreferredSize().width - 10, getHeight() - statusLabel.getPreferredSize().height - 10);
		statusLabel.setText(statusText);
		statusLabel.setBounds(0, 0, statusLabel.getPreferredSize().width, statusLabel.getPreferredSize().height);		
		statusLabel.paint(g2);
		
		g2.setTransform(new AffineTransform());
		
		Point2D pt = getScreenPosition(new Point3d(0,0,0));
		g2.translate(pt.getX(), pt.getY());
		g2.drawLine(-10, 0, 10, 0);
		g2.drawLine(0, 10, 0, -10);
		
		
	}

	public void setState(WorldState state) {
		this.state = state;
		repaint();
	}

	/**
	 * @return the agent
	 */
	public OperatorAgent getAgent() {
		return agent;
	}

	/**
	 * @param agent the agent to set
	 */
	public void setAgent(OperatorAgent agent) {
		this.agent = agent;
	}
}
